package com.example.elm_server_api.filter;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 资源访问授权过滤器
 *
 * @author 张建平
 * @createtime 2022/7/27 下午4:39
 */
@Slf4j
public class CustomAuthorizationFilter extends OncePerRequestFilter {

    private String tokenSecret;

    public CustomAuthorizationFilter(String tokenSecret) {
        this.tokenSecret = tokenSecret;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
            throws ServletException, IOException {

        //登录请求不过滤，不做安全授权
        if(request.getRequestURI().equals("/meituan/login/**")
                || request.getRequestURI().equals("/api/user/register")
        ){
            filterChain.doFilter(request,response);
        } else {
            //从请求标头中获取 token
            String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);

            if(StringUtils.hasText(authorizationHeader)
                    && authorizationHeader.startsWith("Bearer")){
                try {
                    // 获取用户token并验证 token 是否有效
                    String token = authorizationHeader.substring("Bearer ".length());
                    //创建加密算法
                    Algorithm algorithm = Algorithm.HMAC256(tokenSecret);

                    //创建验证器
                    JWTVerifier verifier = JWT.require(algorithm).build();
                    //验证 token，验证失败会产生异常
                    DecodedJWT decodedJWT = verifier.verify(token);
                    //获取主休
                    String username = decodedJWT.getSubject();

                    //用角色名称组装权限列表
                    // Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();

                    //获取 JWT 中的角色列表信息
                    List<String> roles = decodedJWT.getClaim("roles").asList(String.class);//asArray(Class c)
                    // roles.forEach(role -> authorities.add(new SimpleGrantedAuthority(role)));

                    List<GrantedAuthority> authorities = roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());

                    UsernamePasswordAuthenticationToken authenticationToken =
                            new UsernamePasswordAuthenticationToken(username, null, authorities);

                    //非常关键的一步，在安全上下文中设置认证 token
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);

                    filterChain.doFilter(request,response);


                } catch (Exception e) {
                    log.error("Error in login: {}", e.getMessage());
                    response.setHeader("error",e.getMessage());
                    //设置禁止响应状态
                    response.setStatus(HttpStatus.FORBIDDEN.value());

                    //响应主体消息
                    Map<String, String> errors = new HashMap<>();
                    errors.put("error_message", e.getMessage());

                    ObjectMapper objectMapper = new ObjectMapper();
                    objectMapper.writeValue(response.getOutputStream(), errors);
                }
            } else {
                filterChain.doFilter(request,response);
            }
        }
    }
}
